# ~*~ coding: utf-8 ~*~
from flask import request, views, render_template, jsonify
from flask import current_app
from apps.common.utils import timestamp_obj_to_str, fill_date_to_timestamp
from apps.common.mixin import CompatibleWithSelect2Mixin
from apps.common import response
from apps.extensions import db
from ..models import Role, RolePermission
from ..forms import RoleCreateUpdateForm
from ..mixin import PermissionRequiredMixin, LoginRequiredMixin

__all__ = [
    'RoleListAPI', 'RoleListView', 'RoleUpdateView', 'RoleCreateView', 'RoleDeleteView'
]


class RoleListAPI(CompatibleWithSelect2Mixin, PermissionRequiredMixin, LoginRequiredMixin, views.MethodView):
    permission_required = 'perms-role-list'

    def get(self):
        create_time = request.args.get('create_time')
        start_time = end_time = None
        if create_time:
            start_time = fill_date_to_timestamp('start', create_time.split('~')[0])
            end_time = fill_date_to_timestamp('end', create_time.split('~')[1])

        filter_conditions = {
            'and': [
                ('create_time', 'gte', start_time),
                ('create_time', 'lte', end_time),
            ],
            'or': [
                ('name', 'like', request.args.get('search')),
            ],
        }

        # 排序
        sort = request.args.get('sort') or 'create_time'
        order = request.args.get('order') or 'desc'
        order_by_list = [(sort, order), ]

        # 分页
        offset = request.args.get('offset') or 0
        limit = request.args.get('limit') or 12

        # Compatible with select2
        if request.values.get('type') == 'select2':
            filter_conditions, order_by_list, offset, limit = self.select2_queryset()

        roles, count = Role.get_queryset(filter_conditions=filter_conditions,
                                         order_by_list=order_by_list,
                                         offset=offset, limit=limit)
        results = list()
        for role in roles:
            results.append({
                'id': role.id,
                'name': role.name,
                'describe': role.describe,
                'create_time': timestamp_obj_to_str(role.create_time)
            })

        resp = {
            "data": {
                "rows": results,
                "total": count
            }
        }
        return jsonify(resp)


class RoleListView(PermissionRequiredMixin, LoginRequiredMixin, views.MethodView):
    permission_required = 'perms-role-list'

    def get(self):
        return render_template('perms/role_list.html')


class RoleUpdateView(PermissionRequiredMixin, LoginRequiredMixin, views.MethodView):
    permission_required = 'perms-role-update'

    def get(self, pk):
        role = db.session.query(Role).filter(Role.id == str(pk)).first()
        permission_ids = db.session.query(RolePermission.permission_id).\
            filter(RolePermission.role_id == role.id).\
            all()

        if permission_ids:
            permission_ids = ','.join(list(zip(*permission_ids))[0])
        else:
            permission_ids = ''

        content = {
            'id': role.id,
            'name': role.name,
            'describe': role.describe,
            'create_time': timestamp_obj_to_str(role.create_time),
            'permission_ids': permission_ids
        }
        return render_template('perms/role_update.html', **content)

    def post(self, pk):
        form = RoleCreateUpdateForm(request.values)
        instance = db.session.query(Role).get(str(pk))
        if form.validate():
            _clean_data = form.data
            if _clean_data.get('name') != instance.name:
                if db.session.query(Role).filter_by(name=_clean_data.get('name')).count():
                    return response.params_error({
                        'field': 'name',
                        'message': '角色名称不能重复'
                    })
            permissions = _clean_data.pop('permissions').split(',')

            role = instance.update(**_clean_data, commit=False)
            db.session.flush()

            db.session.query(RolePermission).filter(RolePermission.role_id == role.id).delete()
            db.session.bulk_insert_mappings(
                RolePermission,
                [dict(role_id=role.id, permission_id=pid) for pid in permissions]
            )
            db.session.commit()
            return response.success()

        else:
            return response.params_error(data=form.get_error())


class RoleCreateView(PermissionRequiredMixin, LoginRequiredMixin, views.MethodView):
    permission_required = 'perms-role-create'

    def get(self):
        return render_template('perms/role_create.html')

    def post(self):
        form = RoleCreateUpdateForm(request.values)
        if form.validate():
            _clean_data = form.data
            if db.session.query(Role).filter_by(name=_clean_data.get('name')).count():
                return response.params_error({
                    'field': 'name',
                    'message': '角色名称不能重复'
                })
            permissions = _clean_data.pop('permissions').split(',')
            role = Role.create(**_clean_data, commit=False)
            db.session.flush()

            db.session.bulk_insert_mappings(
                RolePermission,
                [dict(role_id=role.id, permission_id=pid) for pid in permissions]
            )
            db.session.commit()
            return response.success()

        else:
            return response.params_error(data=form.get_error())


class RoleDeleteView(PermissionRequiredMixin, LoginRequiredMixin, views.MethodView):
    permission_required = 'perms-role-delete'

    def post(self, pk):
        instance = db.session.query(Role).get(str(pk))
        try:
            instance.delete(commit=False)
            db.session.query(RolePermission).filter(RolePermission.role_id == instance.id).delete()
            db.session.commit()
            return response.success()
        except Exception as e:
            current_app.logger.error(e)
            db.session.rollback()
            return response.server_error(data={
                'message': "出现未知错误，请联系管理员！"
            })
